package com.xyz.apis.utils;

import com.google.common.collect.Maps;
import com.google.common.util.concurrent.RateLimiter;

import java.util.concurrent.ConcurrentMap;

/**
 * User:
 * Date: 2016-11-11
 * Description: No Description
 */
public class CommonRateLimiterManager {
    /**
     * 限流器缓存
     *
     * key:identify+permitsPerSnd
     *
     * value:限流器实例
     * */
    /*private static final Cache<String, RateLimiter> RATE_LIMITER_CACHE = CacheBuilder.newBuilder()
            .maximumSize(100000).expireAfterWrite(60, TimeUnit.SECONDS).build();*/

    //private static final ConcurrentMap<String, RateLimiter> RATE_LIMITER_CACHE =  Maps.newConcurrentMap();

    private static final ConcurrentMap<String, RateLimiter> userResourceLimiterMap = Maps.newConcurrentMap();

    // 10秒请求一次； 一分钟大于6次，需要等一个小时
    private static final ConcurrentMap<Long, RateLimiter> userRequestLimiterMap = Maps.newConcurrentMap();
    // 一分钟限制的数据
    private static final ConcurrentMap<Long, RateLimiter> userTwoLimiterMap = Maps.newConcurrentMap();
    // 一小时限制的数据
    private static final ConcurrentMap<Long, RateLimiter> userThereLimiterMap = Maps.newConcurrentMap();



    /**
     * 申请获取一个许可<p>
     *
     * 同一个 identify 共享一个限速器<p>
     *
     * @param identify 身份信息
     * @param permitsPerSnd 当前的限速值
     */
    /*public static void acquireOnePermit(final String identify, final double permitsPerSnd) {
        try {
            RateLimiter rateLimiter = RATE_LIMITER_CACHE.get(identify, new Callable<RateLimiter>() {

                *//**
                 * Computes a result, or throws an exception if unable to do so.
                 *
                 * @return computed result
                 * @throws Exception if unable to compute a result
                 *//*
                @Override
                public RateLimiter call() throws Exception {
                    System.out.println("已创建限流组件-[identify={0}, permitsPerSnd={1}]."+identify+"--"+
                            permitsPerSnd);
                    return RateLimiter.create(permitsPerSnd);
                }
            });

            rateLimiter.acquire();
        } catch (Exception e) {
            System.out.println("获取限流组件时异常,identify={0},permitsPerSnd={1}."+ identify+"--"+permitsPerSnd);
        }
    }*/

    /**
     * 如果获取到就返回true.否则返回false.
     * 这个是不阻塞当前线程的
     * @param identify
     * @param permitsPerSnd
     */
    /*public static boolean tryAcquireOnePermit(final String identify, final double permitsPerSnd) {
        try {
            RateLimiter rateLimiter = RATE_LIMITER_CACHE.get(identify, new Callable<RateLimiter>() {

                *//**
                 * Computes a result, or throws an exception if unable to do so.
                 *
                 * @return computed result
                 * @throws Exception if unable to compute a result
                 *//*
                @Override
                public RateLimiter call() throws Exception {
                    System.out.println("已创建限流组件-[identify={0}, permitsPerSnd={1}]."+identify+"--"+
                            permitsPerSnd);
                    return RateLimiter.create(permitsPerSnd);
                }
            });

            return rateLimiter.tryAcquire();
        } catch (Exception e) {
            System.out.println("获取限流组件时异常,identify={0},permitsPerSnd={1}."+ identify+"--"+
                    permitsPerSnd);
            return false;
        }
    }*/

    public static Boolean enter(String userKey) {
        long t1 = System.currentTimeMillis();
        //Double qps = resourceMap.get(resource);
        Double qps = 1/60d;// 1秒钟可以访问多小次


        String keySer =  userKey;
        RateLimiter rateLimiter = userResourceLimiterMap.get(keySer);
        if (rateLimiter == null) {
            rateLimiter = RateLimiter.create(qps);

            RateLimiter putByOtherThread = userResourceLimiterMap.putIfAbsent(keySer,rateLimiter);
            if (putByOtherThread != null) {
                rateLimiter = putByOtherThread;
            }
            rateLimiter.setRate(qps);
        }

        //非阻塞
        if (!rateLimiter.tryAcquire()) {
            //限速中，提示用户 失败

            return false;
        } else {
            //正常访问
            return true;
        }

    }

    public static Integer enterOrder(Long userid) {
        Double qps = 1/10d;// 10秒请求一次
        Double qpsfen = 5/60d;// 1分钟访问4次,这里10秒请求一次，会占用一次机会
        Double qpshour = 1/3600d;// 1个小时 锁定
        RateLimiter rateLimiter = userRequestLimiterMap.get(userid);
        RateLimiter rateLimiter2 = userTwoLimiterMap.get(userid);
        RateLimiter rateLimiter3 = userThereLimiterMap.get(userid);
        if (rateLimiter == null) {
            rateLimiter = RateLimiter.create(qps);

            RateLimiter putByOtherThread = userRequestLimiterMap.putIfAbsent(userid,rateLimiter);
            if (putByOtherThread != null) {
                rateLimiter = putByOtherThread;
            }
            rateLimiter.setRate(qps);
        }
        //非阻塞
        if (!rateLimiter.tryAcquire()) {
            //限速中，提示用户 失败
            return -1; // 10秒请求一次
        }
        if (rateLimiter2 == null) {
            rateLimiter2 = RateLimiter.create(qpsfen);
            RateLimiter putByOtherThread = userTwoLimiterMap.putIfAbsent(userid,rateLimiter2);
            if (putByOtherThread != null) {
                rateLimiter2 = putByOtherThread;
            }
            rateLimiter2.setRate(qpsfen);
        }
        //非阻塞
        if (!rateLimiter2.tryAcquire()) {
            //限速中，提示用户 失败
            if(rateLimiter3==null){
                rateLimiter3 = RateLimiter.create(qpshour);

                RateLimiter putByOtherThread = userThereLimiterMap.putIfAbsent(userid,rateLimiter3);
                if (putByOtherThread != null) {
                    rateLimiter3 = putByOtherThread;
                }
                rateLimiter3.setRate(qpshour);
                rateLimiter3.tryAcquire();
            }
            return -2; // 1分钟只能请求6次
        }
        if (rateLimiter3!=null&&!rateLimiter3.tryAcquire()) {
            //限速中，提示用户 失败
            return -3; // 1分钟请求超过6次之后，要限制一个小时
        }
        return 1;

    }
    public static void main(String[] agrs){
        for (int i = 0; i < 10; i++) {


            System.out.println(enterOrder(1000L));
            try {
                Thread.sleep(12000);
            }catch (Exception e){}

        }

    }

}